package com.golxen.framework.netty;


import com.golxen.framework.netty.session.base.ServerLinkedGroup;
import com.golxen.utils.LogUtil;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.*;
import io.netty.channel.epoll.Epoll;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.AttributeKey;

public class NettyServices {


	public static int LINK_COUNT = 4;

	public static final AttributeKey<ServerLinkedGroup> LINKED_CLIENT = AttributeKey.valueOf("LINKED_CLIENT");

	private ChannelFuture channelFuture;
	private EventLoopGroup bossGroup;
	private EventLoopGroup workGroup;

	private int port;

	public static NettyServices start(int port, ChannelHandler handler, String flag) {
		try {
			
			NettyServices nettyServices = new NettyServices();
			
			nettyServices.port = port;
			int nThreads = Runtime.getRuntime().availableProcessors();

			if (Epoll.isAvailable()) {
				nettyServices.bossGroup = new EpollEventLoopGroup(1);
				nettyServices.workGroup = new EpollEventLoopGroup(nThreads);

			} else {
				nettyServices.bossGroup = new NioEventLoopGroup(1);
				nettyServices.workGroup = new NioEventLoopGroup(nThreads);
			}

			ServerBootstrap bootstrap = new ServerBootstrap();
			bootstrap.group(nettyServices.bossGroup, nettyServices.workGroup);
			bootstrap.channel(Epoll.isAvailable() ? EpollServerSocketChannel.class : NioServerSocketChannel.class);
			bootstrap.childHandler(new ServerClientChannelInitializer(flag, handler));

			//允许重复使用本地地址和端口
			bootstrap.option(ChannelOption.SO_REUSEADDR, true);
			//接收缓冲区的大小
			bootstrap.option(ChannelOption.SO_RCVBUF, 1024 * 8);
			//临时存放已完成三次握手的请求的队列的最大长度
			bootstrap.option(ChannelOption.SO_BACKLOG, 128);
			//ByteBuf的分配器(重用缓冲区)
			bootstrap.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);

			//连接保活
			bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
			//关闭Socket的延迟时间
			bootstrap.childOption(ChannelOption.SO_LINGER, 0);
			//禁用Nagle算法(即时发送，不等到将小数据包组装成大的帧)
			bootstrap.childOption(ChannelOption.TCP_NODELAY, true);
			//发送缓冲区
			bootstrap.childOption(ChannelOption.SO_SNDBUF, 1024 * 8);
			//ByteBuf的分配器(重用缓冲区)
			bootstrap.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);

			//缓冲区高低位限制
			bootstrap.childOption(ChannelOption.WRITE_BUFFER_WATER_MARK,
					new WriteBufferWaterMark(1024 * 64, 1024 * 128));

			nettyServices.channelFuture = bootstrap.bind(port);
			nettyServices.channelFuture.sync();
			LogUtil.CONSOLE.info("**** NettyService start port 【{}】", port);
			return nettyServices;

		} catch (Exception e) {
			LogUtil.COMMON.error("init netty " + port + " fail, exception:", e);
			throw new RuntimeException(e);
		}
	}

	public void newStop() {
		try {
			channelFuture.channel().close().sync();
			LogUtil.CONSOLE.info("**** NettyService stop port 【{}】", port);
		} catch (Exception e) {
			LogUtil.COMMON.error("Websocket close error", e);
		}
	}
}
